package com.zmx.job.admin.core.nodedistribute.routestrategy;

import com.zmx.core.dto.HeartInfo;
import com.zmx.core.server.ClientInstanceInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 最佳性能 动态分发
 * @ClassName: BestPerformance
 * @Author zhaomxr
 * @Date 2021-12-22 17:54
 */
@Slf4j
public class BestPerformance {

    private static double lastUsedRate = 1;
    private static double lastIdleUsedRate = 1;
    private static String lastNode = "";

    public static String get() {

        Map<String, Boolean> onLineInstance = ClientInstanceInfo.getOnLineInstance();
        Map<String, HeartInfo> infoInstance = ClientInstanceInfo.getInfoInstance();

        //使用类内部nodeMap,避免同一时刻客户端上下线 影响当前选举
        Map<String, Boolean> nodeMap = new HashMap<String, Boolean>(onLineInstance.size());
        nodeMap.putAll(onLineInstance);
        //使用类内部infoMap,避免同一时刻客户端上下线 影响当前选举
        Map<String, HeartInfo> infoMap = new HashMap<String, HeartInfo>(infoInstance.size());
        infoMap.putAll(infoInstance);

        //计算每个节点的内存使用率和cpu使用率
        for (String node : infoMap.keySet()) {
            //节点必须是存活节点
            if (onLineInstance.get(node) != null) {
                HeartInfo heartInfo = infoMap.get(node);
                //内存使用率
                double usedRate = heartInfo.getMemInfo().get("usedRate") == null ? 1 : Double.valueOf(heartInfo.getMemInfo().get("usedRate"));
                //cpu使用率
                double idleUsedRate = heartInfo.getCpuInfo().get("idleUsedRate") == null ? 1 : Double.valueOf(heartInfo.getCpuInfo().get("idleUsedRate"));

                //先判断内存及cpu使用率最小的节点
                if (usedRate < lastUsedRate && idleUsedRate <= lastIdleUsedRate) {
                    lastNode = node;
                } else if (usedRate < lastUsedRate && idleUsedRate > lastIdleUsedRate) {
                    //如果内存小于上一节点，但是cpu使用率小于75%,那么选择该节点
                    if (idleUsedRate < 0.75) {
                        lastNode = node;
                    }
                } else if (usedRate > lastUsedRate && idleUsedRate < lastIdleUsedRate) {
                    //如果内存使用率相差在12.5%以内 且cpu利用率远低于另一个40%，就以cpu为准
                    if (Math.abs(lastUsedRate - usedRate) < 0.125 && Math.abs(lastIdleUsedRate - idleUsedRate) > 0.4) {
                        lastNode = node;
                    }
                } else if (usedRate < lastUsedRate) {
                    lastNode = node;
                }
            }
        }

        //如果没有找到就默认取第一个
        if (StringUtils.isEmpty(lastNode)) {
            lastNode = onLineInstance.keySet().iterator().next();
        }

        return lastNode;
    }
}
